package com.polaris.live.viewmodel.live

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.StringUtils
import com.polaris.live.common.cacha.CacheUtil
import com.polaris.live.common.cacha.UserManager
import com.polaris.live.common.constant.AppConst
import com.polaris.live.common.constant.BizEventConst
import com.polaris.live.common.constant.CommonConst
import com.polaris.live.common.event.EventMessage
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.common.manager.withCountdown
import com.polaris.live.common.manager.withRetryNow
import com.polaris.live.common.network.AppException
import com.polaris.live.common.network.HTTP_SUCCESS_CODE
import com.polaris.live.common.network.launchLoading
import com.polaris.live.common.network.request
import com.polaris.live.common.network.state.ResultState
import com.polaris.live.common.network.state.paresException
import com.polaris.live.common.network.state.paresResult
import com.polaris.live.common.util.JsonUtils
import com.polaris.live.common.util.ToastGravity
import com.polaris.live.common.util.ViewUtils
import com.polaris.live.constant.LiveConst
import com.polaris.live.im.sfs.COMMAND_LIVE_JOIN
import com.polaris.live.im.sfs.COMMAND_LIVE_PUBLIC_SCREEN
import com.polaris.live.im.sfs.COMMAND_LIVE_QUIT
import com.polaris.live.im.sfs.COMMAND_LIVE_RECOVER
import com.polaris.live.im.sfs.COMMAND_LIVE_STOP
import com.polaris.live.im.sfs.PARTY_LIVEKICKUSER
import com.polaris.live.im.sfs.bean.live.CallSignalingMessage
import com.polaris.live.im.sfs.bean.live.LiveJoinMessage
import com.polaris.live.im.sfs.bean.live.LiveKickUserMessage
import com.polaris.live.im.sfs.bean.live.LiveMsgIdMessage
import com.polaris.live.im.sfs.bean.live.LivePublicScreenMessage
import com.polaris.live.im.sfs.bean.live.LiveQuitMessage
import com.polaris.live.im.sfs.bean.live.LiveStopMessage
import com.polaris.live.im.sfs.bean.live.SendLiveNoticeMessage
import com.polaris.live.im.sfs.bean.live.ext.UserBasicVo
import com.polaris.live.im.sfs.core.SmartFoxManager
import com.polaris.live.im.sfs.core.SmartFoxQueueManager
import com.polaris.live.im.sfs.core.bean.resolveResponse
import com.polaris.live.manager.AppConfigManager
import com.polaris.live.manager.DownFileManager
import com.polaris.live.manager.LiveStateManager
import com.polaris.live.net.gameService
import com.polaris.live.net.homeService
import com.polaris.live.net.liveService
import com.polaris.live.net.userService
import com.polaris.live.popup.GlobalPopupManager
import com.polaris.live.resp.back_resp.CallStartResp
import com.polaris.live.resp.back_resp.CallVo
import com.polaris.live.resp.back_resp.DisplayUserBean
import com.polaris.live.resp.back_resp.InfoOtherResp
import com.polaris.live.resp.back_resp.LiveConsumptionUserVo
import com.polaris.live.resp.back_resp.LiveStopReceiptResp
import com.polaris.live.resp.back_resp.LiveSubsidyIndicatorResp
import com.polaris.live.resp.back_resp.SendMessageBarrageNumberResp
import com.polaris.live.resp.back_resp.UserBackpackBarrageNumberResp
import com.polaris.live.resp.back_resp.UserFreeGiftResp
import com.polaris.live.resp.back_resp.WeekStarResp
import com.polaris.live.resp.event.BackgroundEvent
import com.polaris.live.resp.go_resp.FacesDetectBean
import com.polaris.live.resp.go_resp.LiveIdBean
import com.polaris.live.resp.go_resp.SendGiftBean
import com.polaris.live.translation.R
import com.polaris.live.translation.R.string
import com.polaris.live.ui.live.bean.LiveInitInfo
import com.polaris.live.ui.live.bean.LiveSpectatorBean
import com.polaris.live.utils.BitwiseUtils
import com.polaris.live.utils.StartLiveProxy
import com.polaris.live.utils.file.FileUtils
import com.polaris.live.utils.parseLiveInfo
import kotlinx.coroutines.Job
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
import org.greenrobot.eventbus.EventBus
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.atomic.AtomicBoolean

/**
 * LiveVideoViewModel
 *
 * @author Created by lucas on 2023/11/11 09:22
 * @since 1.0.0
 */
class LiveVideoViewModel : LiveViewModel() {

    var isForegroundClose = true //是否时在前台关闭
    var callInfo: CallVo? = null
    var callBean: CallStartResp? = null
    var callMessage: CallSignalingMessage? = null

    //用户加入直播间
    val joinLiveLiveData = MutableLiveData<ResultState<LiveInitInfo>>()
    fun joinLive(anchorId: Long) {
        viewModelScope.launch {
            joinLiveLiveData.value = StartLiveProxy.launchLiveMessageState(anchorId, {
                SmartFoxQueueManager.sendLiveMessage(
                    COMMAND_LIVE_JOIN,
                    LiveJoinMessage(anchorId = anchorId)
                )
            }, {
                val room = getRoom()
                room?.parseLiveInfo()?.let { variable ->
                    LiveInitInfo(variable, room.userCount)
                }
            })
        }
    }

    /**
     * 检测直播间是否存在
     */
    val detectRoomLiveData = MutableLiveData<ResultState<LiveInitInfo>>()
    fun detectRoom(anchorId: Long) {
        viewModelScope.launch {
            detectRoomLiveData.value = StartLiveProxy.launchLiveMessageState(anchorId, {
                SmartFoxQueueManager.sendLiveMessage(
                    COMMAND_LIVE_JOIN,
                    LiveJoinMessage(anchorId = anchorId, detected = true)
                )
            }, {
                val room = getRoom()
                room?.parseLiveInfo()?.let { variable ->
                    LiveInitInfo(variable, room.userCount)
                }
            })
        }
    }

    //用户恢复加入直播间
    val recoverJoinLiveData = MutableLiveData<Throwable?>()
    fun recoverJoinLive(anchorId: Long, delay: Long? = null) {
        viewModelScope.launch {
            try {
                if (delay != null && delay > 0) {
                    delay(delay)
                }

                SmartFoxQueueManager.sendLiveMessage(
                    COMMAND_LIVE_JOIN,
                    LiveJoinMessage(anchorId = anchorId, reconnected = true)
                )
                recoverJoinLiveData.value = null
            } catch (t: Throwable) {
                recoverJoinLiveData.value = t
            }
        }
    }

    //获取用户信息然后转跳
    val infoUserLiveData = MutableLiveData<ResultState<InfoOtherResp>>()
    fun getInfoUserData(id: Long) {
        val type = BitwiseUtils.bitwiseOperation(
            longArrayOf(UserManager.BASIC_INFORMATION, UserManager.LIVE_INFORMATION)
        )
        request({ userService.getInfoOther(id, type) }, infoUserLiveData)
    }

    //用户退出直播间
    val exitLiveLiveData = MutableLiveData<LiveSpectatorBean?>()
    fun exitLive(anchorId: Long, switchBean: LiveSpectatorBean? = null) {
        viewModelScope.launch {
            val deferred = async {
                withContext(NonCancellable + CoroutineScopeManager.ioDispatcher) {
                    try {
                        SmartFoxQueueManager.sendLiveMessage(
                            COMMAND_LIVE_QUIT,
                            LiveQuitMessage(anchorId)
                        )
                    } catch (_: Throwable) {
                    }
                }
            }

            withTimeoutOrNull(500) {
                deferred.await()
            }

            exitLiveLiveData.postValue(switchBean)
        }
    }

    //通话退出直播间，只有主播调用
    fun callExitLive() {
        viewModelScope.launch {
            try {
                SmartFoxQueueManager.sendLiveMessage(
                    COMMAND_LIVE_QUIT,
                    LiveQuitMessage(UserManager.getUserId())
                )
            } catch (_: Throwable) {
            }
        }
    }

    //恢复直播间，只有主播调用
    val recoverFailureLiveData = MutableLiveData<Throwable>()
    fun recoverLive() {
        viewModelScope.launch {
            try {
                //这里立即重试一次
                withRetryNow {
                    SmartFoxQueueManager.sendLiveMessage(COMMAND_LIVE_RECOVER, LiveMsgIdMessage())
                }
            } catch (t: Throwable) {
                //恢复直播间失败，退出
                recoverFailureLiveData.value = t
            }
        }
    }

    //关闭直播间
    val stopLiveLiveData = MutableLiveData<ResultState<LiveStopReceiptResp>>()
    fun stopLive(liveId: Long, needLoading: Boolean) {
        viewModelScope.launch {
            try {
                if (needLoading) {
                    showLoading(StringUtils.getString(string.loading))
                }

                val resp = SmartFoxQueueManager.sendLiveMessage(
                    COMMAND_LIVE_STOP,
                    LiveStopMessage(liveId)
                )
                val data = resp.receipt.resolveResponse<LiveStopReceiptResp>()
                if (data != null) {
                    stopLiveLiveData.paresResult(data)
                } else {
                    stopLiveLiveData.paresException(NullPointerException("data is null"))
                }
            } catch (t: Throwable) {
                stopLiveLiveData.paresException(t)
            } finally {
                dismissDialog()

                //状态回归正常
                LiveStateManager.changeState(LiveConst.State.NONE)
            }
        }
    }

    //直播人脸截图上传
    fun facesDetect(liveId: Long) {
        viewModelScope.launch(CoroutineScopeManager.ioDispatcher) {
            if (faceState) {
                invokeFacesDetect(liveId)
            } else {
                faceStateWaitTask = Runnable {
                    invokeFacesDetect(liveId)
                }
            }
        }
    }

    private fun invokeFacesDetect(liveId: Long) {
        takeScreenshot(AppConst.UpLoad.FACE) {
            request({ liveService.faceDetect(FacesDetectBean(it, liveId)) }, {})
        }
    }

    //弹幕信息更新
    val barrageNumberLiveData = MutableLiveData<ResultState<UserBackpackBarrageNumberResp>>()

    //发送公屏消息
    fun sendPublicMessage(message: LivePublicScreenMessage) {
        viewModelScope.launch {
            try {
                val data = SmartFoxQueueManager.sendLiveMessage(COMMAND_LIVE_PUBLIC_SCREEN, message)
                if (message.type == 1) { //发送的弹幕
                    if (!data.ext.isNullOrEmpty()) {
                        val bean = JsonUtils.fromJson<SendMessageBarrageNumberResp>(data.ext)
                        bean?.barrageNumber?.let {
                            barrageNumberLiveData.value = ResultState.onAppSuccess(it)
                        }
                    }
                    ToastGravity.showGravity(R.string.published_successfully)
                }

            } catch (t: Throwable) {
                if (t is AppException) {
                    if (t.errCode == CommonConst.ErrorCode.SENDGIFT) {
                        ViewUtils.getAliveTopActivity()?.let { con ->
                            GlobalPopupManager.showRechargePopup(
                                con,
                                this@LiveVideoViewModel,
                                isNeedBottom = true, onRechargeOk = {
                                    EventBus.getDefault().post(EventMessage(BizEventConst.INFO_UPDATA))
                                })
                        }

                    }
                }
                ToastGravity.showGravity(t.message)
            }
        }
    }

    //通话结束回来的等待
    val callEndWaitLiveData = MutableLiveData<Unit>()
    private var callEndWaitJob: Job? = null
    fun callEndWaitResume() {
        callEndWaitJob = viewModelScope.launch {
            try {
                val waitPeriod =
                    AppConfigManager.getConfig(CommonConst.Configs.liveEndWaitPeriod)
                        ?.toLongOrNull()
                        ?: LiveConst.LIVE_END_WAIT_PERIOD

                //这里多加1秒
                delay(waitPeriod + 1000)

                callEndWaitLiveData.value = Unit
            } finally {
                if (callEndWaitJob == coroutineContext[Job]) {
                    callEndWaitJob = null
                }
            }
        }
    }

    fun stopCallEndWaitResume() {
        callEndWaitJob?.cancel()
        callEndWaitJob = null
    }

    private var activitiesCount = 0
    val activitiesScrollLiveData = MutableLiveData<Int>() //请求活动滚动信息刷新

    //直播获取顶部消费列表
    val liveUserCountLiveData = MutableLiveData<Int>()
    val liveConsumeLiveData = MutableLiveData<Pair<Long, List<LiveConsumptionUserVo>>>()
    private var liveConsumeJob: Job? = null
    fun launchConsumeUser(liveId: Long) {
        liveConsumeJob?.cancel()
        liveConsumeJob = viewModelScope.launch {
            try {
                while (isActive) {
                    request({ liveService.liveConsume(liveId) }, {
                        liveConsumeLiveData.value = liveId to it
                    })

                    SmartFoxManager.getLiveRoom()?.userCount?.also {
                        liveUserCountLiveData.value = it
                    }

                    delay(LiveConst.PARTY_LIST_TIME)

                    activitiesCount++

                    if (activitiesCount % 3 == 0) {
                        activitiesScrollLiveData.value = activitiesCount
                    }

                }
            } finally {
                if (liveConsumeJob == coroutineContext[Job]) {
                    liveConsumeJob = null
                }
            }
        }
    }

    //直播间滑动更多逻辑
    val liveLoadMoreLiveData = MutableLiveData<ResultState<DisplayUserBean>>()
    fun getLoadMore(anchorId: Long, delay: Long? = null) {
        viewModelScope.launch {
            if (delay != null) {
                delay(delay)
            }

            request({ homeService.getLiveSingle(1, anchorId) }, liveLoadMoreLiveData)
        }
    }

    //直播心跳
    val liveHeartbeatLiveData = MutableLiveData<Boolean>()
    private var liveHeartbeatFailureCount = 0
    private var liveHeartbeatJob: Job? = null
    fun launchLiveHeartbeat(liveId: Long) {
        liveHeartbeatFailureCount = 0
        liveHeartbeatJob = viewModelScope.launch {
            try {
                while (isActive) {
                    liveHeartbeatFailureCount = try {
                        val resp = liveService.liveCheck(LiveIdBean(liveId))

                        if (resp.code == HTTP_SUCCESS_CODE) {
                            0
                        } else {
                            if (resp.code == CommonConst.ErrorCode.LIVE_NOT_EXIST) {
                                Int.MAX_VALUE
                            } else {
                                liveHeartbeatFailureCount + 1
                            }
                        }
                    } catch (_: Throwable) {
                        liveHeartbeatFailureCount + 1
                    }

                    if (liveHeartbeatFailureCount >= 3) {
                        liveHeartbeatLiveData.value = true
                    }

                    delay(LiveConst.HEARTBEAT_TIME)
                }
            } finally {
                if (liveHeartbeatJob == coroutineContext[Job]) {
                    liveHeartbeatJob = null
                }
            }
        }
    }

    //人脸隐藏显示
    val faceStateLiveData = MutableLiveData<Int>()

    private var faceStateJob: Job? = null

    @Volatile
    private var initializedFaceState = false

    @Volatile
    private var faceState: Boolean = false

    @Volatile
    private var faceStateWaitTask: Runnable? = null

    fun triggerFaceChange(showFace: Boolean, init: Boolean = false) {
        faceState = showFace

        if (showFace) {
            runWaitFaceDetect()
        }

        if (showFace) {
            faceStateJob?.cancel()
            faceStateJob = null
            faceStateLiveData.postValue(-1)
        } else {
            //已经初始化的无视
            if (init && initializedFaceState) {
                return
            } else if (faceStateJob != null) {
                return
            }

            faceStateJob = viewModelScope.launch {
                delay(LiveConst.FACE_TRIGGER_DELAY)
                withCountdown(LiveConst.FACE_STOP_DELAY, 1000, {
                    faceStateLiveData.value = it.toInt()
                }, {
                    if (faceStateJob == coroutineContext[Job]) {
                        faceStateJob = null
                    }

                    if (it == 0L) {
                        faceStateLiveData.value = -2
                    }
                })
            }
        }

        initializedFaceState = true
    }

    private fun runWaitFaceDetect() {
        viewModelScope.launch(CoroutineScopeManager.ioDispatcher) {
            faceStateWaitTask?.run()
            faceStateWaitTask = null
        }
    }

    //试播功能
    val trialCountdownLiveData = MutableLiveData<Long>()
    private var trialCountdownJob: Job? = null
    fun launchTrialCountdown(liveStartTime: Long) {
        trialCountdownJob = viewModelScope.launch {
            val timeInMillis = liveStartTime - CacheUtil.getServerTime()
            withCountdown(timeInMillis, 1000, {
                trialCountdownLiveData.value = it
            }, {
                trialCountdownLiveData.value = -1

                if (trialCountdownJob == coroutineContext[Job]) {
                    trialCountdownJob = null
                }
            })
        }
    }

    /**
     * 计时器
     */
    val timerLiveData = MutableLiveData<Long>()
    private var timerJob: Job? = null
    fun timerdown(liveStartTime: Long) {
        timerJob = viewModelScope.launch {
            val timeInMillis = CacheUtil.getServerTime() - liveStartTime
            timerLiveData.value = timeInMillis
            while (isActive) {
                timerLiveData.value = (timerLiveData.value ?: 0L) + 1000
                delay(1000)
            }
            if (timerJob == coroutineContext[Job]) {
                timerJob = null
            }
        }
    }

    //主播通知消息pag下载
    private var mIsDownloading = AtomicBoolean(false)   //是否正在下载中
    private val mLoadQueue = ConcurrentLinkedQueue<SendLiveNoticeMessage>() //下载队列
    private var mPagJob: Job? = null
    val mDownLoadLiveData = MutableLiveData<SendLiveNoticeMessage>()

    fun downLoadPag(sendLiveNoticeMessage: SendLiveNoticeMessage) {
        if (mIsDownloading.get()) {
            mLoadQueue.add(sendLiveNoticeMessage)
            return
        }
        mIsDownloading.set(true)
        mPagJob = viewModelScope.launch(CoroutineScopeManager.ioDispatcher) {
            try {
                val loadFileCallback =
                    DownFileManager.loadFileCallback(
                        FileUtils.getPagFile(),
                        sendLiveNoticeMessage.titleImage
                    )
                withContext(CoroutineScopeManager.mainDispatcher) {
                    mIsDownloading.set(false)
                    loadFileCallback?.second?.let {
                        mDownLoadLiveData.value = sendLiveNoticeMessage
                    }
                    mLoadQueue.poll()?.let { downLoadPag(it) }
                }
            } finally {
                if (coroutineContext[Job] == mPagJob) {
                    mPagJob = null
                }
            }
        }
    }

    //直播补贴指标
    val mSubsidyLiveData = MutableLiveData<ResultState<LiveSubsidyIndicatorResp>>()
    fun getSubsidy() {
        request({ liveService.subsidies() }, mSubsidyLiveData)
    }

    override fun onCleared() {
        super.onCleared()
        mPagJob?.cancel()
        mPagJob = null
    }

    /**
     * 停止直播的轮询请求
     */
    override fun resetLiveJob() {
        super.resetLiveJob()
        cancelPollingWeeklyStarRank()
        trialCountdownJob?.cancel()
        trialCountdownJob = null
        timerJob?.cancel()
        timerJob = null
        liveConsumeJob?.cancel()
        liveConsumeJob = null
        liveHeartbeatJob?.cancel()
        liveHeartbeatJob = null
        faceStateJob?.cancel()
        faceStateJob = null

        stopCallEndWaitResume()
    }

    private var killJob: Job? = null
    fun killActivityTimeout(time: Long) {
        killJob = viewModelScope.launch {
            try {
                delay(time)
                EventBus.getDefault().post(BackgroundEvent(0))
            } finally {
                if (killJob == coroutineContext[Job]) {
                    killJob = null
                }
            }
        }
    }

    fun stopKillActivityTimeout() {
        killJob?.cancel()
        killJob = null
    }

    /**
     * 周星数据轮询
     */
    private var weeklyStarRankJob: Job? = null

    fun pollingWeeklyStarRank() {
        if (weeklyStarRankJob != null) return
        weeklyStarRankJob = viewModelScope.launch {
            try {
                while (isActive) {
                    getWeeklyStarRank()
                    delay(15000)
                }
            } finally {
                if (weeklyStarRankJob == coroutineContext[Job]) {
                    weeklyStarRankJob = null
                }
            }
        }
    }

    fun cancelPollingWeeklyStarRank() {
        weeklyStarRankJob?.cancel()
        weeklyStarRankJob = null
    }

    //获取周星数据
    val weeklyStarRankData = MutableLiveData<ResultState<WeekStarResp>>()
    fun getWeeklyStarRank() {
        request({ gameService.getWeeklyStarRank() }, weeklyStarRankData)
    }

    /**
     * 踢出房间
     */
    fun kickUser(userid: Long, anchorId: Long) {
        launchLoading {
            try {
                SmartFoxQueueManager.sendLiveMessage(
                    PARTY_LIVEKICKUSER,
                    LiveKickUserMessage(userid, anchorId)
                )
            } catch (t: Throwable) {
                ToastGravity.showGravity(t.message)
            }
        }
    }

    /**
     * 获取礼物红点
     */
    //获取游戏状态
    val mBackGiftRedData = MutableLiveData<ResultState<Boolean>>()
    fun getBackGiftRed() {
        request(
            { userService.getHaveNewBackpack() }, mBackGiftRedData
        )
    }

    //赠送免费礼物
    val mSendFreeGiftLiveData = MutableLiveData<Any>()
    fun sendFreeGift(userbasic: UserBasicVo, gift: UserFreeGiftResp, sourceType: Int, objectId: Long) {
        val giftBean = gift.giftVo
        if (giftBean != null) {
            val sendGiftBean = SendGiftBean(
                userbasic.userId, giftBean.id, 1, sourceType, objectId, gift.backpackId, giftBean.payload
            )
            request({ liveService.sendGift(sendGiftBean) }, {
                ToastGravity.showGravity(string.gift_send_success)
                mSendFreeGiftLiveData.value = it
            }, {
                ToastGravity.showGravity(it.errorMsg)
            })
        }
    }
}